/**
* 版权归 瞄你个汪 所有。
* 使用本代码应遵守相关法律法规和许可证的要求。
*/
package cn.sqlsuper.toolkit;

import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * Field工具类
 * </p>
 *
 * @author 瞄你个汪
 * @since 2024/5/30 8:50
 */
public class ClassTool {
    public final static String PROJECT_PATH = System.getProperty("user.dir");

    /**
     * 获取指定类及其所有父类的所有字段
     * @param clazz 目标类
     * @return 包含所有字段的列表
     */
    public static List<Field> getAllFields(Class<?> clazz) {
        List<Field> allFields = new ArrayList<>();
        while (clazz != null) {
            Field[] declaredFields = clazz.getDeclaredFields();
            allFields.addAll(Arrays.asList(declaredFields));
            clazz = clazz.getSuperclass();
        }
        return allFields;
    }

    /**
     * 根据类和字段名获取字段
     * @param clazz 类
     * @param fieldName 字段名
     */
    public static Field getField(Class<?> clazz, String fieldName) {
        List<Field> allFields = getAllFields(clazz);
        return allFields.stream()
                .filter(x -> x.getName().equals(fieldName))
                .findFirst()
                .orElse(null);
    }

    /**
     * 获取当前资源目录下所有类
     * @return 当前资源目录下所有类
     */
    public static List<Class<?>> getClassesByDirector(String directorPath) {
        if (directorPath == null) directorPath = Thread.currentThread().getClass().getResource("/").getPath().substring(1);

        List<Class<?>> classes = new ArrayList<>();
        Queue<File> queue = new LinkedList<>();
        File director = new File(directorPath);

        queue.add(director);
        while (!queue.isEmpty()) {
            File[] files = queue.remove().listFiles();
            if (files == null) continue;

            for (File file : files) {
                if (file.isDirectory()) {
                    queue.add(file);
                    continue;
                }
                if (file.getName().endsWith(".class")) {
                    // 移除.class后缀并转换为类名
                    String fileName = file.getName();
                    String parentPath = file.getParent();
                    String packageName = parentPath.substring(parentPath.indexOf(PROJECT_PATH) + PROJECT_PATH.length()).replace(System.getProperty("file.separator"), ".");
                    packageName = packageName.substring(packageName.indexOf("classes") + 8);
                    String className = packageName + "." + fileName.substring(0, fileName.length() - 6);
                    try {
                        classes.add(Class.forName(className));
                    } catch (ClassNotFoundException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }
        return classes;
    }

    /**
     * 获取所有枚举类
     * @return 所有枚举类
     */
    public static List<Class<?>> getEnumClasses(List<Class<?>> classes) {
        if (classes == null) classes = getClassesByDirector(null);
        if (classes.isEmpty()) return new ArrayList<>();
        return classes.stream().filter(Class::isEnum).collect(Collectors.toList());
    }

    /**
     * 获取继承clazz的所有类
     * @return 继承clazz的所有类
     */
    public static List<Class<?>> getClassesBySuperclass(List<Class<?>> classes, Class<?> clazz) {
        if (classes == null) classes = getClassesByDirector(null);
        if (classes.isEmpty()) return new ArrayList<>();
        return classes.stream().filter(clazz::isAssignableFrom).collect(Collectors.toList());
    }

    /**
     * 获取实现implClass的所有类
     * @return 实现implClass的所有类
     */
    public static List<Class<?>> getClassesByInterface(List<Class<?>> classes, Class<?> interClass) {
        if (classes == null) classes = getClassesByDirector(null);
        if (classes.isEmpty()) return new ArrayList<>();
        return classes.stream()
                .filter(x -> Arrays.asList(x.getInterfaces()).contains(interClass))
                .collect(Collectors.toList());
    }

    /**
     * 获取带有annoClass注解的所有类
     * @return 带有annoClass注解的所有类
     */
    public static List<Class<?>> getClassesByAnnotation(List<Class<?>> classes, Class<? extends Annotation> annoClass) {
        if (classes == null) classes = getClassesByDirector(null);
        if (classes.isEmpty()) return new ArrayList<>();
        return classes.stream()
                .filter(x -> x.isAnnotationPresent(annoClass))
                .collect(Collectors.toList());
    }

    /**
     * 根据类加载器和包名获取类集合
     * @param classLoader 类加载器
     * @param packageName 包名
     * @return 类集合
     */
    public static List<Class<?>> getClassesByPackageName(ClassLoader classLoader, String packageName) {
        String path = packageName.replace('.', '/');
        return getClassesByDirector(Objects.requireNonNull(classLoader.getResource(path)).getPath());
    }
}
